package cn.monkey.family.server.domain.shop.order;

import cn.monkey.family.data.shop.order.OrderDetail;
import cn.monkey.family.data.shop.order.OrderDetailSelector;
import cn.monkey.family.data.shop.order.OrderMapper;
import com.google.common.base.Function;
import org.mapstruct.factory.Mappers;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.CollectionUtils;

import javax.annotation.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

@Configuration
public class OrderConfig {

    @Bean
    OrderDetailSelector orderDetailSelector(OrderDetailRepository orderDetailRepository,
                                            CacheManager cacheManager) {
        Cache cache = cacheManager.getCache(OrderDetail.KEY);

        return new OrderDetailSelector() {
            @Override
            @Nullable
            public OrderDetail selectById(String id) {
                Function<String, OrderDetail> func = s -> orderDetailRepository.findById(s).orElse(null);
                return cache == null ? func.apply(id) : cache.get(id, () -> func.apply(id));
            }

            @Override
            public Collection<OrderDetail> selectByIds(Collection<String> ids) {
                Function<Collection<String>, Collection<OrderDetail>> func = orderDetailRepository::findAllById;
                if (cache == null) {
                    return func.apply(ids);
                }
                List<OrderDetail> list = ids.stream().map(id -> cache.get(id, OrderDetail.class))
                        .collect(Collectors.toList());
                ids = ids.stream().filter(s -> list.stream().anyMatch(od -> s.equals(od.getSkuId())))
                        .collect(Collectors.toSet());
                if (CollectionUtils.isEmpty(ids)) {
                    return list;
                }
                Collection<OrderDetail> collection = func.apply(ids);
                if (CollectionUtils.isEmpty(collection)) {
                    return list;
                }
                collection.forEach(od -> cache.put(od.getSkuId(), od));
                list.addAll(collection);
                return list;
            }
        };
    }

    @Bean
    OrderMapper orderMapper() {
        return Mappers.getMapper(OrderMapper.class);
    }

    @Bean
    OrderItemBoundChecker orderItemBoundChecker(OrderDetailRepository orderDetailRepository) {
        return new OrderItemBoundChecker(orderDetailRepository);
    }
}
